﻿//-----------------------------------------------------------------------
// <copyright file="RandomAgendaList.cs" company="tuliprules.org">
//     Copyright (c) 2010 tuplelister, tuliprules.org.
// </copyright>
// <summary>This is the RandomAgendaList class.</summary>
//-----------------------------------------------------------------------

namespace Tulip.Engine.ConflictResolution
{
    using System.Collections;
    using System.Globalization;
    using Tuple = Tuples.Tuple;

    /// <summary>
    /// Agenda list for Depth-First conflict resolution strategy.
    /// </summary>
    internal class RandomAgendaList : IAgendaList
    {
        /// <summary>
        /// A hash table containing productions.  The hash table is used to randomise the order of
        /// those productions.
        /// </summary>
        private readonly Hashtable productionList = new Hashtable();

        #region IAgendaQueue Members

        /// <summary>
        /// Gets or sets the count of tuples int he list.
        /// </summary>
        public int Count
        {
            get
            {
                return this.productionList.Count;
            }

            set
            {
            }
        }

        /// <summary>
        /// Adds a production tuple to thje agenda list.
        /// </summary>
        /// <param name="production">The production tuple to be added to the agenda list.</param>
        public void Push(Tuple production)
        {
            this.productionList.Add(production, production);
            production.AgendaTimestamp = this.productionList.Count;
            TraceFactIds("==> Activating '" + production.ProductionName + "': ", production);
        }

        /// <summary>
        /// Removes and returns the next production tuple from the agenda list. 
        /// </summary>
        /// <returns>The next production tuple to be removed from the agenda list.</returns>
        public Tuple Pop()
        {
            Tuple returnProduction = null;

            foreach (Tuple production in this.productionList.Values)
            {
                returnProduction = production;
                break;
            }

            TraceFactIds("FIRE '" + returnProduction.ProductionName + "': ", returnProduction);

            if (returnProduction == null)
            {
                return returnProduction;
            }

            this.productionList.Remove(returnProduction);
            return returnProduction;
        }

        /// <summary>
        /// Returns, but does not remove, the next production tuple in the agenda list.
        /// </summary>
        /// <returns>The next production tuple to be removed from the agenda list.</returns>
        public Tuple Peek()
        {
            Tuple returnProduction = null;

            foreach (Tuple production in this.productionList.Values)
            {
                returnProduction = production;
                break;
            }

            return returnProduction;
        }

        /// <summary>
        /// Removes a production tuple from the agenda list.
        /// </summary>
        /// <param name="production">The production tuple to be removed from the agenda list.</param>
        public void Remove(Tuple production)
        {
            this.productionList.Remove(production);
            TraceFactIds("<== Deactivating '" + production.ProductionName + "': ", production);
        }

        #endregion

        /// <summary>
        /// Returns a string of fact ID information for tracing purposes.
        /// </summary>
        /// <param name="initMsg">Initial string message.</param>
        /// <param name="production">A production containing a list if fact Identifiers.</param>
        [System.Diagnostics.Conditional("DEBUG")]
        private static void TraceFactIds(string initMsg, Tuple production)
        {
            var factIds = string.Empty;

            if (production.Identifiers == null)
            {
                System.Diagnostics.Debug.WriteLine(initMsg + factIds);
                return;
            }

            var ids = production.Identifiers;

            for (var idx = 0; idx < ids.Count; idx++)
            {
                factIds += "f" + ids[idx].ToString(CultureInfo.InvariantCulture) + ", ";
            }

            System.Diagnostics.Debug.WriteLine(initMsg + factIds);
        }
    }
}
